﻿namespace Blaze.Framework
{
    using System.Collections.Generic;
    using UnityEngine;

    /// <summary>
    /// 用于创建可复用的Yield对象。
    /// <code>
    /// Usage:
    ///    yield return new WaitForSeconds(1.0f);    =>      yield return YielderFactory.WaitForSeconds(1.0f);
    ///    yield return new WaitForEndOfFrame();     =>      yield return YielderFactory.EndOfFrame;
    ///    yield return new WaitForFixedUpdate();    =>      yield return YielderFactory.FixedUpdate;
    /// </code>
    /// </summary>
    public static class YielderFactory
    {
        /// <summary>
        /// 获取或设置一个值，表示是否启用生成可复用的对象。
        /// </summary>
        public static bool Enabled = true;

        /// <summary>
        /// 获取已创建的<see cref="YieldInstruction"/>的数量。
        /// </summary>
        public static int Counter { get; private set; }

        /// <summary>
        /// 清理所有缓存的<see cref="WaitForSeconds"/>对象。
        /// </summary>
        public static void ClearWaitForSeconds()
        {
            mWaitForSecondsYielders.Clear();
        }

        private static readonly WaitForEndOfFrame mEndOfFrame = new WaitForEndOfFrame();
        private static readonly WaitForFixedUpdate mFixedUpdate = new WaitForFixedUpdate();
        private static readonly Dictionary<float, WaitForSeconds> mWaitForSecondsYielders = new Dictionary<float, WaitForSeconds>(100, new FloatComparer());
        private static readonly Dictionary<float, WaitForSecondsRealtime> mWaitForSecondsRealtimeYielders = new Dictionary<float, WaitForSecondsRealtime>(100, new FloatComparer());

        #region YieldInstrucions

        public static WaitForEndOfFrame WaitForEndOfFrame()
        {
            Counter++;
            return Enabled ? mEndOfFrame : new WaitForEndOfFrame();
        }

        public static WaitForFixedUpdate WaitForFixedUpdate()
        {
            Counter++;
            return Enabled ? mFixedUpdate : new WaitForFixedUpdate();
        }

        public static WaitForSeconds WaitForSeconds(float seconds)
        {
            Counter++;

            if (!Enabled)
                return new WaitForSeconds(seconds);

            WaitForSeconds waitForSeconds;

            if (!mWaitForSecondsYielders.TryGetValue(seconds, out waitForSeconds))
                mWaitForSecondsYielders.Add(seconds, waitForSeconds = new WaitForSeconds(seconds));

            return waitForSeconds;
        }

        public static WaitForSecondsRealtime WaitForSecondsRealtime(float seconds)
        {
            Counter++;

            if (!Enabled)
                return new WaitForSecondsRealtime(seconds);

            WaitForSecondsRealtime waitForSeconds;

            if (!mWaitForSecondsRealtimeYielders.TryGetValue(seconds, out waitForSeconds))
                mWaitForSecondsRealtimeYielders.Add(seconds, waitForSeconds = new WaitForSecondsRealtime(seconds));

            return waitForSeconds;
        }

        #endregion
    }
}